var private = {}, self = null,
library = null, modules = null;

/**
 * Creates instance of Accounts API. Use *modules.api.accounts* to get existing object.
 *
 * @param cb - Callback
 * @param _library - Object that contains helpers.
 * @constructor
 */
function Accounts(cb, _library) {
	self = this;
	library = _library;
	cb(null, self);
}

/**
 * Open account in Lisk.
 *
 * @param secret - Secret of account.
 * @param {Accounts~openCallback} cb - Callback handles response from Lisk.
 */
Accounts.prototype.open = function (secret, cb) {
	var message = {
		call: "accounts#open",
		args: {
			secret: secret
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~openCallback
 * @param error - Error of api execution.
 * @param response - Response of api execution.
 * @param response.account - Opened account.
 * @param response.account.address - Address of opened account.
 * @param response.account.balance - Balance of account.
 * @param response.account.unconfirmedBalance - Unconfirmed balance of account.
 * @param response.account.publicKey - Public key of account.
 * @param response.account.secondSignature - Is second signature enabled on account.
 * @param response.account.secondPublicKey - Public key of second signature.
 * @param response.account.multisignatures - Is this account under multisignature.
 * @param response.account.unconfirmedSignature - Is this account contains second signature, but second signature not confirmed yet.
 * @param response.account.u_multisignatures - Is this account under unconfirmed multisignature.
 */

/**
 * Get balance of account.
 *
 * @param address - Address of account
 * @param {Accounts~balanceCallback} cb - Callback handle response from Lisk.
 */
Accounts.prototype.getBalance = function (address, cb) {
	var message = {
		call: "accounts#getBalance",
		args: {
			address: address
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~balanceCallback
 * @param error - Error of api execution.
 * @param response - Response of api execution.
 * @param response.balance - Balance of account.
 * @param response.unconfirmedBalance - Unconfirmed balance of account.
 */

/**
 * Get public key of account.
 * @param address - Address of account.
 * @param {Accounts~publicKeyCallback} cb - Callback handle response from Lisk.
 */
Accounts.prototype.getPublickey = function (address, cb) {
	var message = {
		call: "accounts#getPublickey",
		args: {
			address: address
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~publicKeyCallback
 * @param error - Error of api execution.
 * @param response - Response of api execution.
 * @param response.publicKey - Public key of account in hex.
 */


/**
 * Generate public key by secret.
 *
 * @param secret - Secret of account.
 * @param {Accounts~genPublickeyCallback} cb - Callback handle response.
 */
Accounts.prototype.generatePublickey = function (secret, cb) {
	var message = {
		call: "accounts#generatePublickey",
		args: {
			secret: secret
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~genPublickeyCallback
 * @param error - Error of api execution.
 * @param response - Response of api execution.
 * @param response.publicKey - Public key generated by secret.
 */

/**
 * Get delegates that have votes from account.
 *
 * @param address - Address of account.
 * @param {Accounts~delegatesCallback} cb - Callback handle response from Lisk.
 */
Accounts.prototype.getDelegates = function (address, cb) {
	var message = {
		call: "accounts#getDelegates",
		args: {
			address: address
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~delegatesCallback
 * @param error - Error from api execution.
 * @param response - Response from api execution.
 * @param response.delegates - Array of delegates.
 * @param response.delegates[0].username - Username of delegate.
 * @param response.delegates[0].vote - Amount of votes for delegate.
 * @param response.delegates[0].address - Address of delegate.
 * @param response.delegates[0].publicKey - Public key of delegate.
 * @param response.delegates[0].rate - Position of delegate in delegates list.
 * @param response.delegates[0].productivity - Productivity of delegate.
 */


/**
 * Get fee amount of vote for delegate.
 * @param {Accounts~delegatesFeeCallback) cb - Callback handle response.
 */
Accounts.prototype.getDelegatesFee = function (cb) {
	var message = {
		call: "accounts#getDelegatesFee",
		args: {}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~delegatesFeeCallback
 * @param error - Error from api call execution.
 * @param response - Response from api call execution.
 * @param response.fee - Amount of fee that need to vote for delegate.
 */

/**
 * Vote for delegate.
 * @param secret - Secret of account.
 * @param publicKey - Public key of account (optional).
 * @param secondSecret - Second secret, if second signature enabled (optional).
 * @param {Accounts~addDelegateCallback} cb - Callback handle response.
 */
Accounts.prototype.addDelegates = function (secret, publicKey, secondSecret, cb) {
	var message = {
		call: "accounts#addDelegates",
		args: {
			secret: secret,
			publicKey: publicKey,
			secondSecret: secondSecret
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~addDelegateCallback
 * @param error - Error from api execution
 * @param response - Response from api execution
 * @param response.transactionId - Id of transaction sent.
 */

/**
 * Get fee amount to pay for username.
 * @param {Accounts~usernameFeeCallback} cb - Callback handle response.
 */
Accounts.prototype.getUsernameFee = function (cb) {
	var message = {
		call: "accounts#getUsernameFee",
		args: {}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~usernameFeeCallback
 * @param error - Error from api execution.
 * @param response - Response from api execution.
 * @param response.fee - Fee to register username.
 */

/**
 * Register username on account.
 *
 * @param secret - Secret of account.
 * @param publicKey - Public key of account (optional).
 * @param secondSecret - Second secret of account, if second signature enabled (optional).
 * @param username - Username of account to register.
 * @param {Accounts~addUsernameCallback} cb - Callback handle response.
 */
Accounts.prototype.addUsername = function (secret, publicKey, secondSecret, username, cb) {
	var message = {
		call: "accounts#addUsername",
		args: {
			secret: secret,
			publicKey: publicKey,
			secondSecret: secondSecret,
			username: username
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~addUsernameCallback
 * @param error - Error from api execution.
 * @param response - Response from api execution.
 * @param response.transactionId - id of transaction sent.
 */

/**
 * Get account from Lisk.
 *
 * @param address - address of account.
 * @param {Accounts~getAccountCallback} cb - Callback handle response.
 */
Accounts.prototype.getAccount = function (address, cb) {
	var message = {
		call: "accounts#getAccount",
		args: {
			address: address
		}
	};

	library.sandbox.sendMessage(message, cb);
}

/**
 * @callback Accounts~getAccountCallback
 * @param error - Error of api execution.
 * @param response - Response of api execution.
 * @param response.
 */

Accounts.prototype.onBind = function (_modules) {
	modules = _modules;
}

module.exports = Accounts;
